/*
 * Copyright (c) 2011 Nokia Corporation.
 */

#include "levelcontroller.h"
#include "levelmodel.h"
#include "level.h"

#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <QMessageBox>

LevelController::LevelController(Level *level,QObject *parent) :
    QObject(parent)
{
    /***********************************************************************************************
    *Create a level model and a IAPClient object.                                                  *
    ***********************************************************************************************/
    m_Model = new LevelModel(this);
#if defined(IAP_ENABLED)
    m_IAPClient = new IAPClient(this);
#endif
    /***********************************************************************************************
    *Set the level object.                                                                         *
    ***********************************************************************************************/
    m_level = level;

    /***********************************************************************************************
    *Register metatype for IAPClient::ProductData, to be able to use QueuedConnection.             *
    ***********************************************************************************************/
#if defined(IAP_ENABLED)
    qRegisterMetaType<IAPClient::ProductData>("IAPClient::ProductData");
#endif

    /***********************************************************************************************
    *Make connections.                                                                             *
    ***********************************************************************************************/
#if defined(IAP_ENABLED)
    connect(m_IAPClient,SIGNAL(productDataReceived(int,QString,IAPClient::ProductData)),
            this,SLOT(productDataReceved(int,QString,IAPClient::ProductData)),Qt::QueuedConnection);
    connect(m_IAPClient,SIGNAL(restorableProductsReceived(int,QString,IAPClient::ProductList)),
            this,SLOT(restorableProductsReceived(int,QString,IAPClient::ProductList)));
    connect(m_IAPClient,SIGNAL(userAndDeviceDataReceived(int,QString,QString,QString,QString,QString,QString)),
            this,SLOT(userAndDeviceDataReceived(int,QString,QString,QString,QString,QString,QString)));

    connect(m_IAPClient,SIGNAL(purchaseCompleted(int,QString,QString)),
            this,SLOT(purchaseCompleted(int,QString,QString)));
    connect(m_IAPClient,SIGNAL(purchaseFlowFinished(int)),
            this,SLOT(purchaseFlowFinished(int)));

    connect(m_IAPClient,SIGNAL(restorationCompleted(int,QString,QString)),
            this,SLOT(restorationCompleted(int,QString,QString)));
    connect(m_IAPClient,SIGNAL(restorationFlowFinished(int)),
            this,SLOT(restorationFlowFinished(int)));
#endif
    /**********************************************************************************************/

    /***********************************************************************************************
    *Load items and set the default theme.                                                         *
    ***********************************************************************************************/
    loadItems();
    face = ":/images/face-smile.png";
}

void LevelController::load(int index)
{
    /***********************************************************************************************
    *Create a ModelIndex for the given index.                                                      *
    ***********************************************************************************************/
    QModelIndex i = m_Model->index(index);
    if(i.isValid()){
        /*******************************************************************************************
        *If index is valid, extract levelId and type.                                              *
        *******************************************************************************************/
        QString levelId = m_Model->data(i,LevelModel::LevelIdRole).toString();
        QString levelType = m_Model->data(i,LevelModel::LevelType).toString();
        if(levelId != LEVEL_INVALID){
            /***************************************************************************************
            *If type == Level, trigger level loading.                                              *
            ***************************************************************************************/
            if(levelType == "Level" &&
                    m_level->load(QString("%1.xml").arg(levelId)))
                emit levelReload();
            /***************************************************************************************
            *If type == Theme, extract theme name and set new theme.                               *
            ***************************************************************************************/
            else if(levelType == "Theme"){
                face = QString(":/images/face-%1.png")
                        .arg(m_Model->data(i,LevelModel::LevelNameRole).toString());
                emit faceChanged();
            }
        }
    }
}

void LevelController::buy(int index)
{
    /***********************************************************************************************
    *Set initial id to LEVEL_INVALID.                                                              *
    ***********************************************************************************************/
    QString itemId = LEVEL_INVALID;
    /***********************************************************************************************
    *Create a ModelIndex for the given index.                                                      *
    ***********************************************************************************************/
    QModelIndex i = m_Model->index(index);

    if(i.isValid())
        /*******************************************************************************************
        *If index is valid, extract levelId.                                                       *
        *******************************************************************************************/
        itemId = m_Model->data(i,LevelModel::LevelIdRole).toString();

    if(itemId != LEVEL_INVALID){
        /*******************************************************************************************
        *If id valid, call the IAP purchase method.                                                *
        *******************************************************************************************/
#if defined(IAP_ENABLED)
        int requestId = m_IAPClient->purchaseProduct(itemId,IAPClient::ForcedAutomaticRestoration);
        if(requestId > 0){
            /***************************************************************************************
            *If requestId valid, extract item name and add a new entry to the request queue.       *
            ***************************************************************************************/
            QString name = m_Model->data(i,LevelModel::LevelNameRole).toString();
            levelRequests.insert(requestId,QPair<QString,QString>(itemId,name));
        }
#endif
    }
}

/***************************************************************************************************
*Simple access methods.                                                                            *
***************************************************************************************************/
LevelModel* LevelController::getLevelModel() const
{
    return m_Model;
}

QString LevelController::getFace() const
{
    return face;
}
/**************************************************************************************************/

#if defined(IAP_ENABLED)
void LevelController::productDataReceved(int requestId,QString status,IAPClient::ProductData data)
{
    /***********************************************************************************************
    *Check response status.                                                                        *
    ***********************************************************************************************/
    if(status.compare("OK",Qt::CaseInsensitive) == 0){
        /*******************************************************************************************
        *Set initial id,name and type to LEVEL_INVALID and unlocked false.                         *
        *******************************************************************************************/
        QString id = LEVEL_INVALID;
        QString name = LEVEL_INVALID;
        QString type = LEVEL_INVALID;
        bool unlocked = false;
        /*******************************************************************************************
        *Check the request type by looking in the right queue.                                     *
        *******************************************************************************************/
        if(levelRequests.contains(requestId)){
            /***************************************************************************************
            *If requested item is a Level, extract id and name, set type to Level.                 *
            *Check if the file "itemId.xml" exists, if positive the level has been unlocked.       *
            ***************************************************************************************/
            QPair<QString,QString> idName = levelRequests.take(requestId);
            id = idName.first;
            name = idName.second;
            type = "Level";
            unlocked = QFile::exists(QString("%1.xml").arg(id));
        }else if(themeRequests.contains(requestId)){
            /***************************************************************************************
            *If requested item is a Theme, extract id and name, set type to Theme.                 *
            *Check if the file "itemId" exists, if positive the theme has been unlocked.           *
            ***************************************************************************************/
            QPair<QString,QString> idName = themeRequests.take(requestId);
            id = idName.first;
            name = idName.second;
            type = "Theme";
            unlocked = QFile::exists(QString("%1").arg(id));
        }
        if(type != LEVEL_INVALID){
            /***************************************************************************************
            *If item  type set, create and populate a new LevelData struct.                        *
            ***************************************************************************************/
            LevelData levelData;
            levelData.id = id;
            levelData.data = data;
            levelData.name = name;
            levelData.type = type;
            levelData.unlocked = unlocked;
            /***************************************************************************************
            *Add item to model.                                                                    *
            ***************************************************************************************/
            m_Model->setLevelData(levelData);
        }
        /*******************************************************************************************
        *Call request item data, to request next items data retrieval.                             *
        *******************************************************************************************/
        requestItemData();
    }
}

void LevelController::restorableProductsReceived(int requestId,QString status,
                                                 IAPClient::ProductList data)
{
}

void LevelController::userAndDeviceDataReceived(int requestId,QString account,QString imei,QString imsi,
                                                QString country,QString language,QString deviceModel)
{
}

void LevelController::purchaseCompleted(int requestId,QString status,QString purchaseTicked)
{
    /***********************************************************************************************
    *Check if the request queue contains the requestId.                                            *
    ***********************************************************************************************/
    if(levelRequests.contains(requestId)){
        /*******************************************************************************************
        *Check response status.                                                                    *
        *******************************************************************************************/
        if(status.compare("OK",Qt::CaseInsensitive) == 0){
            /***************************************************************************************
            *If status == OK, unlock purchase item.                                                *
            ***************************************************************************************/
            unlock(levelRequests.value(requestId).first,purchaseTicked);
        }else if(status.compare("RestorableProduct",Qt::CaseInsensitive) == 0){
            /***************************************************************************************
            *If status == RestorableProduct, start the product restoration flow.                   *
            ***************************************************************************************/
            int resotreRequestId = m_IAPClient->restoreProduct(levelRequests.value(requestId).first);
            if(resotreRequestId > 0)
                levelRequests.insert(resotreRequestId,levelRequests.take(requestId));
        }
    }
}

void LevelController::purchaseFlowFinished(int requestId)
{
    /***********************************************************************************************
    *Remove the request form the queue. Emit the hack signal to hide the software keys.            *
    ***********************************************************************************************/
    levelRequests.remove(requestId);
    emit hack();
}

void LevelController::restorationCompleted(int requestId,QString status,QString purchaseTicked)
{
    /***********************************************************************************************
    *Check if the request queue contains the requestId.                                            *
    ***********************************************************************************************/
    if(levelRequests.contains(requestId)){
        /*******************************************************************************************
        *Check response status.                                                                    *
        *******************************************************************************************/
        if(status.compare("OK",Qt::CaseInsensitive) == 0)
            /***************************************************************************************
            *If status == OK, unlock purchase item.                                                *
            ***************************************************************************************/
            unlock(levelRequests.value(requestId).first,purchaseTicked);
    }
}

void LevelController::restorationFlowFinished(int requestId)
{
    /***********************************************************************************************
    *Remove the request form the queue. Emit the hack signal to hide the software keys.            *
    ***********************************************************************************************/
    levelRequests.remove(requestId);
    emit hack();
}
#endif
void LevelController::loadItems()
{
    /***********************************************************************************************
    *Check if the file "Item.data" exists.                                                         *
    ***********************************************************************************************/
    if(QFile::exists("Items.data")){
        /*******************************************************************************************
        *Open the file in read-only mode.                                                          *
        *******************************************************************************************/
        QFile dataFile("Items.data");
        if(dataFile.open(QIODevice::ReadOnly)){
            /***************************************************************************************
            *Create a QTextStream to read the files contents.                                      *
            ***************************************************************************************/
            QTextStream readStream(&dataFile);
            while(!readStream.atEnd())
            {
                /***********************************************************************************
                *Read line, append read lines to the itemLines list ignoring comment lines.        *
                ***********************************************************************************/
                QString line = readStream.readLine();
                if(line.startsWith("#")) continue;
                itemLines.append(line);
            }
            /***************************************************************************************
            *Call request item data, to request first items data retrieval.                        *
            ***************************************************************************************/
            requestItemData();
        }
    }
}

void LevelController::requestItemData()
{
    /***********************************************************************************************
    *Check if there are any pending lines.                                                         *
    ***********************************************************************************************/
    if(itemLines.count() > 0)
    {
        /*******************************************************************************************
        *Split the line using ';'.                                                                 *
        *******************************************************************************************/
        QStringList lineContent = itemLines.takeFirst().split(";");
        /*******************************************************************************************
        *Check if the line contains exactly 3 elements.                                            *
        *******************************************************************************************/
        if(lineContent.count() == 3){
            /***************************************************************************************
            *Check item type and add the request to the appropriate queue.                         *
            ***************************************************************************************/
#if defined(IAP_ENABLED)
            if(lineContent.at(1).compare("LEVEL",Qt::CaseInsensitive) == 0){
                QString name = lineContent.at(2);
                int requestId = m_IAPClient->getProductData(lineContent.at(0));
                levelRequests.insert(requestId,QPair<QString,QString>(lineContent.at(0),name));
            }else if(lineContent.at(1).compare("THEME",Qt::CaseInsensitive) == 0){
                QString name = lineContent.at(2);
                int requestId = m_IAPClient->getProductData(lineContent.at(0));
                themeRequests.insert(requestId,QPair<QString,QString>(lineContent.at(0),name));
            }
#endif
        }
    }
}

void LevelController::unlock(QString itemId,QString purchaseTicket)
{
    /***********************************************************************************************
    *The unlocking process implemented here is for presentation purposes only.                     *
    *A truly correct unlocking process needs to involve purchaseTicket validation via the          *
    *Ticket Verification API and downloading the content form a dedicated server.                  *
    ***********************************************************************************************/


    Q_UNUSED(purchaseTicket)
    /***********************************************************************************************
    *Extract LevelData identified by itemId from the model.                                        *
    ***********************************************************************************************/
    LevelData level = m_Model->getById(itemId);
    if(level.id != LEVEL_INVALID){
        /*******************************************************************************************
        *If level is valid, set unlocked to true.                                                  *
        *******************************************************************************************/
        level.unlocked = true;
        /*******************************************************************************************
        *Check item type.                                                                          *
        *******************************************************************************************/
        if(level.type == "Level"){
            /***************************************************************************************
            *Create level file.                                                                    *
            ***************************************************************************************/
            QFile source(QString(":/levels/%1.xml").arg(level.name));
            source.open(QIODevice::ReadOnly);
            QFile levelFile(QString("%1.xml").arg(itemId));
            levelFile.open(QIODevice::WriteOnly|QIODevice::Truncate);
            QTextStream stream(&levelFile);
            stream << source.readAll();
        }else if(level.type == "Theme"){
            /***************************************************************************************
            *Create theme file.                                                                    *
            ***************************************************************************************/
            QFile levelFile(QString("%1").arg(itemId));
            levelFile.open(QIODevice::WriteOnly|QIODevice::Truncate);
            QTextStream stream(&levelFile);
            stream << level.name;
        }
        /*******************************************************************************************
        *Overwrite model item data                                                                 *
        *******************************************************************************************/
        m_Model->setLevelData(level);
    }
}
